package kms

import (
	"context"
	"errors"
	"fmt"
	openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
	kmssdk "github.com/alibabacloud-go/kms-20160120/v3/client"
	"github.com/alibabacloud-go/tea/tea"
	"github.com/aliyun/alibabacloud-kms-agent/internal/conf"
	"github.com/aliyun/credentials-go/credentials"
	"os"
	"strings"
)

const (
	InstanceGatewayDomainSuffix = "cryptoservice.kms.aliyuncs.com"
)

type KeyManagementService struct {
	smClient SMInterface
	config   *openapi.Config
}

func NewKeyManagementService(cfg conf.KmsConfig) (*KeyManagementService, error) {
	// default credentials: https://help.aliyun.com/zh/sdk/developer-reference/v2-manage-go-access-credentials?spm=a2c4g.11186623.help-menu-262060.d_1_9_1_2.33a45c4fAoE9MW&scm=20140722.H_2579531._.OR_help-T_cn~zh-V_1#3ca299f04bw3c
	credentialClient, err := credentials.NewCredential(nil)
	if err != nil {
		return nil, err
	}

	config := &openapi.Config{
		Credential:     credentialClient,
		RegionId:       tea.String(*cfg.Region),
		ReadTimeout:    tea.Int(3 * 1000),
		ConnectTimeout: tea.Int(3 * 1000),
		Protocol:       tea.String("https"),
	}

	if *cfg.Endpoint != "" {
		config.Endpoint = tea.String(*cfg.Endpoint)
	}

	if *cfg.Endpoint != "" && strings.HasSuffix(*cfg.Endpoint, InstanceGatewayDomainSuffix) {
		if *cfg.CaFilePath != "" {
			data, err := os.ReadFile(*cfg.CaFilePath)
			if err != nil {
				return nil, fmt.Errorf("open ca file faaild:%w", err)
			}
			config.Ca = tea.String(string(data))
		} else {
			if ca, ok := RegionIdAndCaMap[*cfg.Region]; !ok {
				return nil, errors.New("instance gateway private CA not found")
			} else {
				config.Ca = tea.String(ca)
			}
		}
	}

	smClient, err := newSecretManagerClient(config)
	if err != nil {
		return nil, err
	}

	return &KeyManagementService{smClient: smClient, config: config}, nil
}

func (kms *KeyManagementService) GetSecretInfo(ctx context.Context, secretId, versionId, versionStage string) (string, error) {
	getSecretRequest := &kmssdk.GetSecretValueRequest{
		FetchExtendedConfig: tea.Bool(true),
		SecretName:          tea.String(secretId),
		VersionStage:        tea.String(versionStage),
		VersionId:           tea.String(versionId),
	}

	ret, err := kms.smClient.GetSecretValue(ctx, getSecretRequest)
	if err != nil {
		return "", err
	}
	return ret.String(), nil
}

func (kms *KeyManagementService) SelfCheck() error {
	err := kms.smClient.SelfCheck()
	if err != nil {
		return fmt.Errorf("secret manager client self check falied: %w", err)
	}
	return nil
}

func (kms *KeyManagementService) GetCredentialType() string {
	cred, _ := kms.config.Credential.GetCredential()
	return *cred.Type
}
